package com.hopes.bizz.emergency.statistic.serivce.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hopes.bizz.common.core.constant.CommonConstant;
import com.hopes.bizz.common.core.util.DateUtils;
import com.hopes.bizz.emergency.common.api.feign.RemoteParkBasicService;
import com.hopes.bizz.emergency.common.constant.PlanDicConstant;
import com.hopes.bizz.emergency.common.constant.enums.ParkEmergencySysDictEnum;
import com.hopes.bizz.emergency.drill.dto.ErEmergencyDrillDTO;
import com.hopes.bizz.emergency.drill.entity.ErActualDrillEntity;
import com.hopes.bizz.emergency.drill.service.ErActualDrillService;
import com.hopes.bizz.emergency.drill.service.ErDrillPlanService;
import com.hopes.bizz.emergency.drill.vo.ErEmergencyCompanyDrillPopulationVO;
import com.hopes.bizz.emergency.drill.vo.ErEmergencyDrillVO;
import com.hopes.bizz.emergency.plan.entity.ErEmergencyPlanEntity;
import com.hopes.bizz.emergency.plan.service.EmergencyParkPlanService;
import com.hopes.bizz.emergency.plan.service.ErEmergencyPlanService;
import com.hopes.bizz.emergency.plan.service.ErGovernmentEmergencyPlanService;
import com.hopes.bizz.emergency.resources.entity.*;
import com.hopes.bizz.emergency.resources.service.*;
import com.hopes.bizz.emergency.statistic.serivce.GisService;
import com.hopes.bizz.emergency.stastic.vo.*;
import com.hopes.boss.admin.api.entity.SysDictItem;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.common.core.constant.SecurityConstants;
import com.hopes.boss.common.core.exception.BizException;
import com.hopes.boss.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author cx
 * @Description 一张图
 * @time 2024/1/17 16:34
 */
@Service("gisService")
@RequiredArgsConstructor
public class GisServiceImpl implements GisService {

    private final EmergencyParkPlanService emergencyParkPlanService;
    private final ErEmergencyPlanService erEmergencyPlanService;
    private final ErGovernmentEmergencyPlanService erGovernmentEmergencyPlanService;
    private final RemoteParkBasicService remoteParkBasicService;
    private final ErWarehouseService erWarehouseService;
    private final ErMaterialService erMaterialService;
    private final ErCarService erCarService;
    private final ErTeamService erTeamService;
    private final ErProtectTargetService erProtectTargetService;
    private final ErDrillPlanService erDrillPlanService;
    private final ErActualDrillService erActualDrillService;

    @Override
    public EmergencyPlanLevelVO emergencyPlanLevel() {
        long parkCount = emergencyParkPlanService.count(Wrappers.lambdaQuery());
        long companyCount = erEmergencyPlanService.count(Wrappers.lambdaQuery());
        long governmentCount = erGovernmentEmergencyPlanService.count(Wrappers.lambdaQuery());
        EmergencyPlanLevelVO emergencyPlanLevelVO = new EmergencyPlanLevelVO();
        emergencyPlanLevelVO.setParkPlanCount(parkCount);
        emergencyPlanLevelVO.setCompanyPlanCount(companyCount);
        emergencyPlanLevelVO.setGovernmentPlanCount(governmentCount);
        return emergencyPlanLevelVO;
    }

    @Override
    public EmergencyPlanHazardVO emergencyPlanHazard() {
            Integer hazardCount = remoteParkBasicService.gethazHazardSourceList(SecurityConstants.FROM_IN).getData();

        LambdaQueryWrapper<ErEmergencyPlanEntity> queryWrapper = Wrappers.<ErEmergencyPlanEntity>lambdaQuery().eq(ErEmergencyPlanEntity::getHazardFlag, CommonConstant.boolean_true_string);
        List<ErEmergencyPlanEntity> planList = erEmergencyPlanService.list(queryWrapper);
        //对hazard去重
        List<ErEmergencyPlanEntity> distinctHazardList = planList.stream()
                .collect(Collectors.toMap(ErEmergencyPlanEntity::getHazard, er -> er, (existing, replacement) -> existing))
                .values()
                .stream()
                .collect(Collectors.toList());

        EmergencyPlanHazardVO emergencyPlanHazardVO = new EmergencyPlanHazardVO();
        if (!planList.isEmpty()&& hazardCount != 0) {
            // 计算并设置 finishRate 保留两位小数
            double rate = (double) distinctHazardList.size() / hazardCount;
            // 保留两位小数
            rate = Math.round(rate * 100.0) / 100.0;
            emergencyPlanHazardVO.setRate(rate);
        }
        else {
            // 处理 hazCount 为0的情况
            emergencyPlanHazardVO.setRate(0.0);
        }
        emergencyPlanHazardVO.setPlanHazardCount(planList.size());
        emergencyPlanHazardVO.setHazardCount(hazardCount);

        return emergencyPlanHazardVO;
    }

    @Override
    public EmergencyCompanyPlanStateVO emergencyCompanyPlanState() {
        List<ErEmergencyPlanEntity> planList = erEmergencyPlanService.list();
        //根据过期状态分类
        Map<Integer, Long> countByStatus = planList.parallelStream()
                .filter(e -> Objects.nonNull(e.getOverdueStatus()))
                .collect(Collectors.groupingBy(ErEmergencyPlanEntity::getOverdueStatus, Collectors.counting()));

        Map<Integer, List<ErEmergencyPlanEntity>> listByStatus = planList.parallelStream()
                .filter(e -> Objects.nonNull(e.getOverdueStatus()))
                .collect(Collectors.groupingBy(ErEmergencyPlanEntity::getOverdueStatus, Collectors.toList()));

        EmergencyCompanyPlanStateVO emergencyCompanyPlanStateVO = new EmergencyCompanyPlanStateVO();
        emergencyCompanyPlanStateVO.setNormalCount(countByStatus.getOrDefault(PlanDicConstant.NORMAL, 0L));
        emergencyCompanyPlanStateVO.setExpiredCount(countByStatus.getOrDefault(PlanDicConstant.EXPIRED, 0L));
        emergencyCompanyPlanStateVO.setApproachExpiredCount(countByStatus.getOrDefault(PlanDicConstant.APPROACH_EXPIRED, 0L));
        emergencyCompanyPlanStateVO.setExpiredList(listByStatus.getOrDefault(PlanDicConstant.EXPIRED, null));
        emergencyCompanyPlanStateVO.setApproachExpiredList(listByStatus.getOrDefault(PlanDicConstant.APPROACH_EXPIRED, null));
        return emergencyCompanyPlanStateVO;
    }

    @Override
    public EmergencyWarehouseLevelVO emergencyWarehouseLevel() {
        List<ErWarehouseEntity> planList = erWarehouseService.list();
        //根据物资库级别分类
        Map<Integer, Long> countByLevel = planList.parallelStream()
                .filter(e -> Objects.nonNull(e.getMaterialLevel()))
                .collect(Collectors.groupingBy(ErWarehouseEntity::getMaterialLevel, Collectors.counting()));
        EmergencyWarehouseLevelVO vo = new EmergencyWarehouseLevelVO();
        vo.setGovernmentWarehouseCount(countByLevel.getOrDefault(PlanDicConstant.WAREHOUSE_LEVEL_GOVERNMENT, 0L));
        vo.setParkWarehouseCount(countByLevel.getOrDefault(PlanDicConstant.WAREHOUSE_LEVEL_PARK, 0L));
        vo.setCompanyWarehouseCount(countByLevel.getOrDefault(PlanDicConstant.WAREHOUSE_LEVEL_COMPANY, 0L));
        vo.setTotalWarehouseCount(Long.valueOf(countByLevel.size()));
        return vo;
    }

    @Override
    public EmergencyMaterialOverdueStatusVO emergencyMaterialOverdueStatus() {
        List<ErMaterialEntity> materialList = erMaterialService.list();
        //根据过期状态分类
        Map<Integer, Long> countByStatus = materialList.parallelStream()
                .filter(e -> Objects.nonNull(e.getSatus()))
                .collect(Collectors.groupingBy(ErMaterialEntity::getSatus, Collectors.counting()));

        EmergencyMaterialOverdueStatusVO vo = new EmergencyMaterialOverdueStatusVO();
        vo.setNormalCount(countByStatus.getOrDefault(PlanDicConstant.NORMAL, 0L));
        vo.setExpiredCount(countByStatus.getOrDefault(PlanDicConstant.EXPIRED, 0L));
        vo.setApproachExpiredCount(countByStatus.getOrDefault(PlanDicConstant.APPROACH_EXPIRED, 0L));
        return vo;
    }

    @Override
    public EmergencyCarlOverdueStatusVO emergencyCarOverdueStatus() {
        List<ErCarEntity> carList = erCarService.list();
        //根据过期状态分类
        Map<Integer, Long> countByStatus = carList.parallelStream()
                .filter(e -> Objects.nonNull(e.getOverdueStatus()))
                .collect(Collectors.groupingBy(ErCarEntity::getOverdueStatus, Collectors.counting()));

        EmergencyCarlOverdueStatusVO vo = new EmergencyCarlOverdueStatusVO();
        vo.setNormalCount(countByStatus.getOrDefault(PlanDicConstant.NORMAL, 0L));
        vo.setExpiredCount(countByStatus.getOrDefault(PlanDicConstant.EXPIRED, 0L));
        vo.setApproachExpiredCount(countByStatus.getOrDefault(PlanDicConstant.APPROACH_EXPIRED, 0L));
        return vo;
    }

    @Override
    public EmergencyTeamOverdueStatusVO emergencyTeamOverdueStatus() {
        List<ErTeamEntity> teamList = erTeamService.list();
        //根据过期状态分类
        Map<Integer, Long> countByStatus = teamList.parallelStream()
                .filter(e -> Objects.nonNull(e.getOverdueStatus()))
                .collect(Collectors.groupingBy(ErTeamEntity::getOverdueStatus, Collectors.counting()));

        EmergencyTeamOverdueStatusVO vo = new EmergencyTeamOverdueStatusVO();
        vo.setNormalCount(countByStatus.getOrDefault(PlanDicConstant.NORMAL, 0L));
        vo.setExpiredCount(countByStatus.getOrDefault(PlanDicConstant.EXPIRED, 0L));
        vo.setApproachExpiredCount(countByStatus.getOrDefault(PlanDicConstant.APPROACH_EXPIRED, 0L));
        return vo;
    }

    @Override
    public EmergencyResourcesTypeVO emergencyMaterialEqType() {

        final List<SysDictItem> orgMaterialTypeList = DictResolver.getItemsByType(ParkEmergencySysDictEnum.emergency_tree_material_type);
        List<SysDictItem> materialTypeList = orgMaterialTypeList.stream()
                .filter(item -> item.getParentId() != null && item.getParentId().equals(item.getDictId()))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(materialTypeList) ) {
            throw new BizException("物资分类获取失败！");
        }
        final List<ErMaterialEntity> materialList = erMaterialService.list(
                Wrappers.<ErMaterialEntity>lambdaQuery().isNotNull(ErMaterialEntity::getMaterialEquipmentType)
                        .select(ErMaterialEntity::getId, ErMaterialEntity::getMaterialEquipmentType));
        final EmergencyResourcesTypeVO vo = new EmergencyResourcesTypeVO();

        final List<String> materialTypeCollect = materialTypeList.stream().map(SysDictItem::getCode)
                .filter(StrUtil::isNotEmpty).collect(Collectors.toList());

        vo.setTypeList(materialTypeList);
        vo.setStatusCountMap(buildIntegerType(materialTypeCollect, materialList, ErMaterialEntity::getMaterialEquipmentType));
        return vo;
    }

    @Override
    public EmergencyResourcesTypeVO emergencyCarType() {
        final List<SysDictItem> carTypeList = DictResolver.getItemsByType(ParkEmergencySysDictEnum.emergency_car_type);
        if (CollUtil.isEmpty(carTypeList) ) {
            throw new BizException("车辆分类获取失败！");
        }
        final List<ErCarEntity> carList = erCarService.list(
                Wrappers.<ErCarEntity>lambdaQuery().isNotNull(ErCarEntity::getCarType)
                        .select(ErCarEntity::getId, ErCarEntity::getCarType));
        final EmergencyResourcesTypeVO vo = new EmergencyResourcesTypeVO();

        final List<String> carTypeCollect = carTypeList.stream().map(SysDictItem::getCode)
                .filter(StrUtil::isNotEmpty).collect(Collectors.toList());

        vo.setTypeList(carTypeList);
        vo.setStatusCountMap(buildIntegerType(carTypeCollect, carList, ErCarEntity::getCarType));
        return vo;
    }

    @Override
    public EmergencyResourcesTypeVO emergencyTeamType() {
        final List<SysDictItem> teamTypeList = DictResolver.getItemsByType(ParkEmergencySysDictEnum.emergency_special_team_type);
        if (CollUtil.isEmpty(teamTypeList) ) {
            throw new BizException("队伍分类获取失败！");
        }
        final List<ErTeamEntity> teamList = erTeamService.list(
                Wrappers.<ErTeamEntity>lambdaQuery().isNotNull(ErTeamEntity::getTeamType)
                        .select(ErTeamEntity::getId, ErTeamEntity::getTeamType));
        final EmergencyResourcesTypeVO vo = new EmergencyResourcesTypeVO();

        final List<String> teamTypeCollect = teamTypeList.stream().map(SysDictItem::getCode)
                .filter(StrUtil::isNotEmpty).collect(Collectors.toList());

        vo.setTypeList(teamTypeList);
        vo.setStatusCountMap(buildIntegerType(teamTypeCollect, teamList, ErTeamEntity::getTeamType));
        return vo;
    }

    @Override
    public EmergencyResourcesTypeVO emergencyProtectTargetType() {
        final List<SysDictItem> protectTargetList = DictResolver.getItemsByType(ParkEmergencySysDictEnum.emergency_protect_target_type);
        if (CollUtil.isEmpty(protectTargetList) ) {
            throw new BizException("保护对象分类获取失败！");
        }
        final List<ErProtectTargetEntity> teamList = erProtectTargetService.list(
                Wrappers.<ErProtectTargetEntity>lambdaQuery().isNotNull(ErProtectTargetEntity::getProtectTargetType)
                        .select(ErProtectTargetEntity::getId, ErProtectTargetEntity::getProtectTargetType));
        final EmergencyResourcesTypeVO vo = new EmergencyResourcesTypeVO();

        final List<String> protectTargetCollect = protectTargetList.stream().map(SysDictItem::getCode)
                .filter(StrUtil::isNotEmpty).collect(Collectors.toList());

        vo.setTypeList(protectTargetList);
        vo.setStatusCountMap(buildIntegerType(protectTargetCollect, teamList, ErProtectTargetEntity::getProtectTargetType));
        return vo;
    }

    @Override
    public List<ErEmergencyDrillVO> emergencyCompanyDrillStatistic(ErEmergencyDrillDTO dto) {
        Page page = new Page();
        List<ErEmergencyDrillVO> records = erDrillPlanService.getDrillOverviewPage(page, dto).getRecords();
        return records;
    }

    @Override
    public List<ErEmergencyCompanyDrillPopulationVO> emergencyCompanyDrillPopulation(Integer year) {
        Date beginTime = DateUtils.parseDate(year + "-01-01", "yyyy-MM-dd");
        Date endTime = DateUtils.parseDate(year + "-12-31", "yyyy-MM-dd");
        List<ErActualDrillEntity> actualDrillList = erActualDrillService.list(Wrappers.<ErActualDrillEntity>lambdaQuery()
                .ge(Objects.nonNull(beginTime),ErActualDrillEntity::getDrillBeginTime, beginTime)
                .le(Objects.nonNull(endTime),ErActualDrillEntity::getDrillBeginTime, endTime));

        Map<Long, Integer> summaryMap = actualDrillList.stream()
                .collect(Collectors.groupingBy(ErActualDrillEntity::getOrgId,
                        Collectors.summingInt(ErActualDrillEntity::getDrillPersons)));
        List<ErEmergencyCompanyDrillPopulationVO> populationVOList = summaryMap.entrySet().stream()
                .map(entry -> new ErEmergencyCompanyDrillPopulationVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        return populationVOList;
    }

    @Override
    public List<ErActualDrillEntity> emergencyCompanyDrillTable(Integer year) {
        Date beginTime = DateUtils.parseDate(year + "-01-01", "yyyy-MM-dd");
        Date endTime = DateUtils.parseDate(year + "-12-31", "yyyy-MM-dd");
        List<ErActualDrillEntity> actualDrillList = erActualDrillService.list(Wrappers.<ErActualDrillEntity>lambdaQuery()
                .ge(Objects.nonNull(beginTime),ErActualDrillEntity::getDrillBeginTime, beginTime)
                .le(Objects.nonNull(endTime),ErActualDrillEntity::getDrillBeginTime, endTime));
        return actualDrillList;
    }

    private <T> Map<String, Integer> buildLongType(List<String> typeCollect, List<T> collection, Function<T, Long> mapper) {
        final Map<String, Integer> planTypeMap = initResList(typeCollect);
        if (CollUtil.isEmpty(collection)) {
            return planTypeMap;
        }
        final Map<Long, Long> listMap = collection.parallelStream().filter(e -> Objects.nonNull(mapper.apply(e))).collect(Collectors.groupingBy(mapper, Collectors.counting()));
        for (Map.Entry<Long, Long> entry : listMap.entrySet()) {
            planTypeMap.put(entry.getKey().toString(), entry.getValue().intValue());
        }
        planTypeMap.put("total", planTypeMap.values().stream().mapToInt(Integer::intValue).sum());
        return planTypeMap;
    }

    private <T> Map<String, Integer> buildIntegerType(List<String> typeCollect, List<T> collection, Function<T, Integer> mapper) {
        final Map<String, Integer> planTypeMap = initResList(typeCollect);
        if (CollUtil.isEmpty(collection)) {
            return planTypeMap;
        }
        final Map<Integer, Long> listMap = collection.parallelStream().filter(e -> Objects.nonNull(mapper.apply(e))).collect(Collectors.groupingBy(mapper, Collectors.counting()));
        for (Map.Entry<Integer, Long> entry : listMap.entrySet()) {
            planTypeMap.put(entry.getKey().toString(), entry.getValue().intValue());
        }
        planTypeMap.put("total", planTypeMap.values().stream().mapToInt(Integer::intValue).sum());
        return planTypeMap;
    }

    /**
     * 初始化数据
     *
     * @param typeCollect 类型
     * @return 结果集
     */
    private Map<String, Integer> initResList(List<String> typeCollect) {
        final HashMap<String, Integer> res = new HashMap<>();
        if (CollUtil.isEmpty(typeCollect)) {
            return res;
        }
        typeCollect.forEach(item -> res.put(item, 0));
        res.put("total", 0);
        return res;
    }
}
